package Listeners;

import RuntimeInfo.State;
import ShapeModel.*;

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

public class CanvasListeners {

    /**
     * @return Canvas区域的鼠标事件监听器，监听鼠标点击和鼠标进入的事件
     */
    public static MouseListener getCanvasMouseListener() {
        return new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                super.mousePressed(e);
                State.pressPoint = e.getPoint();


                // 如果未选择类型或没有点击鼠标左键，则取消聚焦，并且监听函数结束
                if (State.curType == 0 || e.getButton() != MouseEvent.BUTTON1) {
                    State.loseFocus();
                    return;
                }

                if (State.canCreate) {
                    CADShape newShape = null;
                    switch (State.curType) {
                        case State.LINE -> newShape = new CADLine(e.getX(), e.getY(), e.getX() + 1, e.getY() + 1,
                                State.shapeList.size(), State.curColor, State.curStroke);
                        case State.ELLIPSE -> newShape = new CADEllipse(e.getX(), e.getY(), 1, 1,
                                State.shapeList.size(), State.curColor, State.curStroke);
                        case State.RECTANGLE -> newShape = new CADRectangle(e.getX(), e.getY(), 1, 1,
                                State.shapeList.size(), State.curColor, State.curStroke);
                        case State.TEXT -> newShape = new CADText(e.getX(), e.getY(), 1, 1,
                                State.shapeList.size(), State.curColor, State.curStroke, State.text, new Font(Font.MONOSPACED, Font.PLAIN, 1));
                    }
                    State.focusOn(newShape);
                    State.shapeList.add(newShape);
                }

                State.canvas.repaint();
            }

            @Override
            /**
             * 主要是用于判断聚焦的形状的位置
             */
            public void mouseClicked(MouseEvent e) {
                super.mouseClicked(e);
                // 如果为了画图，或者不是用左键点击，无视click监听
                if (State.curType != State.NONTYPE || e.getButton() != MouseEvent.BUTTON1) return;

                CADShape chosen = null;
                for (CADShape shape : State.shapeList) {
                    if (shape.contains(e.getPoint())) {
                        if (chosen == null || shape.getZ() > chosen.getZ()) {// 对z轴进行判断
                            chosen = shape;
                        }
                    }
                }
                if (chosen != null) {
                    State.focusOn(chosen);
                } else {// 如果没有找到，就失去聚焦
                    State.loseFocus();
                    State.canvas.setCursor(Cursor.getDefaultCursor());
                }
                State.canvas.repaint();

            }

            @Override
            public void mouseEntered(MouseEvent e) {
                super.mouseEntered(e);
                if (State.curType != 0) { // 如果可以绘图，就将光标设为绘图样式
                    State.canvas.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
                }
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                super.mouseReleased(e);
                State.pressPoint = null;
                State.canCreate = false; // 只有再次点击绘制，才可以创建新图形
                State.canvas.setCursor(Cursor.getDefaultCursor());
                State.canvas.repaint();
            }
        };
    }


    /**
     * @return Canvas区域的鼠标移动事件监听器，监听鼠标移动和拖拽的事件
     */
    public static MouseMotionListener getCanvasMouseMotionListener() {
        return new MouseMotionListener() {
            @Override
            public void mouseDragged(MouseEvent e) {
                if (State.current == null) return;
                Rectangle2D bound = State.current.getBounds2D();
                switch (State.cursorState) {
                    case State.CREATE -> {
                        if (State.current instanceof CADEllipse) {
                            Point2D origin = State.originFocusPoint, dst = (Point2D) origin.clone();
                            double dd = Math.min(
                                    Math.abs(e.getX() - origin.getX()),
                                    Math.abs(e.getY() - origin.getY())
                            );
                            double dx = (e.getX() >= origin.getX()) ? dd : -dd;
                            double dy = (e.getY() >= origin.getY()) ? dd : -dd;
                            dst.setLocation(
                                    origin.getX() + dx,
                                    origin.getY() + dy

                            );
                            State.current.setPos(origin, dst);


                        } else {
                            State.current.setPos(State.originFocusPoint, e.getPoint());
                        }

                    }
                    case State.DRAG -> {
                        State.current.move(e.getX() - State.pressPoint.getX(), e.getY() - State.pressPoint.getY());
                        State.pressPoint = e.getPoint();
                    }
                    case State.LEFT -> {
                        State.current.resize(0, 0, e.getX() - State.pressPoint.getX(), 0);
                        if (bound.getMinX() >= bound.getMaxX()) State.cursorState = State.RIGHT;
                        State.pressPoint = e.getPoint();
                    }
                    case State.RIGHT -> {
                        State.current.resize(0, 0, 0, e.getX() - State.pressPoint.getX());
                        if (bound.getMinX() >= bound.getMaxX()) State.cursorState = State.LEFT;
                        State.pressPoint = e.getPoint();
                    }
                    case State.TOP -> {
                        State.current.resize(e.getY() - State.pressPoint.getY(), 0, 0, 0);
                        if (bound.getMinY() >= bound.getMaxY()) State.cursorState = State.BOTTOM;
                        State.pressPoint = e.getPoint();
                    }
                    case State.BOTTOM -> {
                        State.current.resize(0, e.getY() - State.pressPoint.getY(), 0, 0);
                        if (bound.getMinY() >= bound.getMaxY()) State.cursorState = State.TOP;
                        State.pressPoint = e.getPoint();
                    }
                }


                State.canvas.repaint();


            }

            @Override
            public void mouseMoved(MouseEvent e) {
                if (State.current == null) return;

                Rectangle2D bound = State.current.getBounds2D();


                if (!State.current.contains(e.getPoint())) {
                    if (State.canCreate) {
                        State.cursorState = State.CREATE;

                    } else {
                        State.cursorState = State.FREE;
                        State.canvas.setCursor(Cursor.getDefaultCursor());
                    }


                } else {
                    if (e.getX() <= bound.getMinX() + 4) {
                        State.cursorState = State.LEFT;
                        State.canvas.setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR));
                    } else if (e.getY() <= bound.getMinY() + 4) {
                        State.cursorState = State.TOP;
                        State.canvas.setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
                    } else if (e.getX() >= bound.getMaxX() - 4) {
                        State.cursorState = State.RIGHT;
                        State.canvas.setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
                    } else if (e.getY() >= bound.getMaxY() - 4) {
                        State.cursorState = State.BOTTOM;
                        State.canvas.setCursor(Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR));
                    } else {
                        State.cursorState = State.DRAG;
                        State.canvas.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
                    }
                }


            }
        };
    }


}
